#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""检测服务模块

综合检测服务，集成检测引擎、结果处理器和性能监控，提供统一的高级检测接口
"""

import logging
import time
import threading
import numpy as np
from typing import List, Dict, Optional, Any, Tuple, Union
import cv2
from pathlib import Path

from core.detection.detector_manager import get_detector_manager, DetectorManager
from core.detection.result_processor import get_result_processor, ResultProcessor
# 使用动态导入来导入根目录下的config.py文件
import sys
import os
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))))
import importlib.util
# 动态导入根目录下的config.py
spec = importlib.util.spec_from_file_location("root_config", os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))), "config.py"))
root_config = importlib.util.module_from_spec(spec)
spec.loader.exec_module(root_config)
# 从动态导入的模块中获取函数
get_config = root_config.get_config
get_all_configs = root_config.get_all_configs

# 设置日志记录器
logger = logging.getLogger(__name__)

class DetectionService:
    """检测服务
    
    提供高级的目标检测、跟踪和结果处理功能
    """
    
    def __init__(self):
        """初始化检测服务"""
        # 获取配置
        self.config = get_all_configs()
        
        # 获取检测器管理器和结果处理器
        self.detector_manager = get_detector_manager()
        self.result_processor = get_result_processor()
        
        # 服务状态
        self.running = False
        self.service_status = 'initializing'
        
        # 线程安全锁
        self._lock = threading.RLock()
        
        # 性能指标
        self.performance_stats = {
            'total_detections': 0,
            'total_processing_time': 0,
            'avg_processing_time': 0,
            'detections_per_second': 0,
            'last_reset_time': time.time()
        }
        
        # 加载默认模型（如果配置了）
        self._load_default_models()
        
        # 启动服务
        self.running = True
        self.service_status = 'running'
        
        logger.info("DetectionService初始化完成")
    
    def _load_default_models(self):
        """加载默认模型"""
        try:
            # 从配置中获取默认模型配置
            default_models = self.config.get('default_models', [])
            
            for model_config in default_models:
                # 创建检测引擎
                engine_id = model_config.get('engine_id', 'default')
                engine_type = model_config.get('engine_type', 'yolo')
                model_path = model_config.get('model_path')
                device = model_config.get('device', 'auto')
                
                if model_path:
                    logger.info(f"加载默认模型: {engine_id} (路径: {model_path})")
                    self.detector_manager.create_engine(
                        engine_id=engine_id,
                        engine_type=engine_type,
                        model_path=model_path,
                        device=device,
                        **model_config.get('kwargs', {})
                    )
                else:
                    logger.warning(f"默认模型 '{engine_id}' 没有指定路径，跳过加载")
            
        except Exception as e:
            logger.error(f"加载默认模型失败: {str(e)}")
    
    def detect(self, image: Union[np.ndarray, str], **kwargs) -> Dict[str, Any]:
        """
        执行目标检测
        
        Args:
            image: 输入图像（numpy数组或文件路径）
            **kwargs:
                - engine_id: 使用的检测引擎ID
                - visualize: 是否可视化结果
                - apply_processing: 是否应用结果处理
                - confidence_threshold: 置信度阈值
                - nms_threshold: NMS阈值
                - target_classes: 目标类别过滤
            
        Returns:
            Dict: 检测结果，包含 'detections' 字段
        """
        start_time = time.time()
        
        try:
            # 准备图像
            image_array, image_info = self._prepare_image(image)
            
            # 选择检测引擎
            engine_id = kwargs.get('engine_id')
            previous_engine_id = None
            if engine_id:
                engine = self.detector_manager.get_engine(engine_id)
                if engine is None:
                    raise ValueError(f"检测引擎 '{engine_id}' 不存在")
                previous_engine = self.detector_manager.get_active_engine()
                previous_engine_id = self._get_engine_id_by_instance(previous_engine)
                self.detector_manager.set_active_engine(engine_id)
            
            # 检测参数
            detect_kwargs = self._prepare_detect_kwargs(kwargs)
            
            # 执行检测
            detections = self.detector_manager.detect(image_array, **detect_kwargs)
            
            # 恢复之前的引擎
            if engine_id and previous_engine_id:
                self.detector_manager.set_active_engine(previous_engine_id)
            
            # 应用结果处理
            if kwargs.get('apply_processing', True):
                detections = self.result_processor.process(detections, image_info)
            
            # 可视化结果（如果需要）
            visualized_image = None
            if kwargs.get('visualize', False):
                engine = self.detector_manager.get_active_engine()
                visualized_image = engine.visualize_results(image_array, detections)
            
            # 计算处理时间
            processing_time = time.time() - start_time
            
            # 更新性能统计
            self._update_performance_stats(processing_time, len(detections))
            
            # 返回结果
            result = {
                'detections': detections,
                'processing_time': processing_time,
                'timestamp': time.time(),
                'image_info': image_info,
                'model_info': self.detector_manager.get_active_engine().get_model_info()
            }
            
            if visualized_image is not None:
                result['visualized_image'] = visualized_image
            
            return result
            
        except Exception as e:
            logger.error(f"检测失败: {str(e)}", exc_info=True)
            raise
    
    def track(self, image: Union[np.ndarray, str], **kwargs) -> Dict[str, Any]:
        """
        执行目标跟踪
        
        Args:
            image: 输入图像（numpy数组或文件路径）
            **kwargs:
                - engine_id: 使用的跟踪引擎ID
                - visualize: 是否可视化结果
                - apply_processing: 是否应用结果处理
                - tracking_config: 跟踪配置
            
        Returns:
            Dict: 跟踪结果，包含 'tracked_objects' 字段
        """
        start_time = time.time()
        
        try:
            # 准备图像
            image_array, image_info = self._prepare_image(image)
            
            # 选择跟踪引擎
            engine_id = kwargs.get('engine_id')
            previous_engine_id = None
            if engine_id:
                engine = self.detector_manager.get_engine(engine_id)
                if engine is None:
                    raise ValueError(f"跟踪引擎 '{engine_id}' 不存在")
                previous_engine = self.detector_manager.get_active_engine()
                previous_engine_id = self._get_engine_id_by_instance(previous_engine)
                self.detector_manager.set_active_engine(engine_id)
            
            # 更新跟踪配置（如果提供）
            if 'tracking_config' in kwargs:
                engine_to_update = self.detector_manager.get_engine(engine_id) if engine_id else self.detector_manager.get_active_engine()
                if engine_to_update and hasattr(engine_to_update, 'set_tracking_config'):
                    engine_to_update.set_tracking_config(kwargs['tracking_config'])
            
            # 执行跟踪
            tracked_objects = self.detector_manager.track(image_array, **kwargs)
            
            # 恢复之前的引擎
            if engine_id and previous_engine_id:
                self.detector_manager.set_active_engine(previous_engine_id)
            
            # 应用结果处理
            if kwargs.get('apply_processing', True):
                tracked_objects = self.result_processor.process(tracked_objects, image_info)
            
            # 可视化结果（如果需要）
            visualized_image = None
            if kwargs.get('visualize', False):
                engine = self.detector_manager.get_active_engine()
                visualized_image = engine.visualize_results(
                    image_array, 
                    tracked_objects, 
                    show_confidence=True, 
                    show_tracks=True,
                    tracked_objects=tracked_objects
                )
            
            # 计算处理时间
            processing_time = time.time() - start_time
            
            # 更新性能统计
            self._update_performance_stats(processing_time, len(tracked_objects))
            
            # 返回结果
            result = {
                'tracked_objects': tracked_objects,
                'processing_time': processing_time,
                'timestamp': time.time(),
                'image_info': image_info,
                'model_info': self.detector_manager.get_active_engine().get_model_info()
            }
            
            if visualized_image is not None:
                result['visualized_image'] = visualized_image
            
            return result
            
        except Exception as e:
            logger.error(f"跟踪失败: {str(e)}", exc_info=True)
            raise
    
    def batch_detect(self, images: List[Union[np.ndarray, str]], **kwargs) -> Dict[str, Any]:
        """批量执行目标检测
        
        Args:
            images: 图像列表（numpy数组或文件路径）
            **kwargs:
                - engine_id: 使用的检测引擎ID
                - visualize: 是否可视化结果
                - apply_processing: 是否应用结果处理
            
        Returns:
            Dict: 批量检测结果
        """
        start_time = time.time()
        
        try:
            # 准备图像
            prepared_images = []
            image_infos = []
            for image in images:
                image_array, image_info = self._prepare_image(image)
                prepared_images.append(image_array)
                image_infos.append(image_info)
            
            # 选择检测引擎
            engine_id = kwargs.get('engine_id')
            if engine_id:
                engine = self.detector_manager.get_engine(engine_id)
                if engine is None:
                    raise ValueError(f"检测引擎 '{engine_id}' 不存在")
                previous_engine_id = self._get_engine_id_by_instance(self.detector_manager.get_active_engine())
                self.detector_manager.set_active_engine(engine_id)
            
            # 检测参数
            detect_kwargs = self._prepare_detect_kwargs(kwargs)
            
            # 执行批量检测
            batch_results = self.detector_manager.batch_detect(prepared_images, **detect_kwargs)
            
            # 恢复之前的引擎
            if engine_id and previous_engine_id:
                self.detector_manager.set_active_engine(previous_engine_id)
            
            # 应用结果处理
            if kwargs.get('apply_processing', True):
                processed_results = []
                for detections, image_info in zip(batch_results, image_infos):
                    processed_detections = self.result_processor.process(detections, image_info)
                    processed_results.append(processed_detections)
                batch_results = processed_results
            
            # 可视化结果（如果需要）
            visualized_images = []
            if kwargs.get('visualize', False):
                engine = self.detector_manager.get_active_engine()
                for i, (image_array, detections) in enumerate(zip(prepared_images, batch_results)):
                    visualized_image = engine.visualize_results(image_array, detections)
                    visualized_images.append(visualized_image)
            
            # 计算处理时间
            processing_time = time.time() - start_time
            
            # 计算平均每张图像处理时间
            avg_processing_time = processing_time / len(images)
            
            # 更新性能统计
            total_detections = sum(len(detections) for detections in batch_results)
            self._update_performance_stats(processing_time, total_detections)
            
            # 返回结果
            result = {
                'batch_results': batch_results,
                'total_processing_time': processing_time,
                'avg_processing_time_per_image': avg_processing_time,
                'total_detections': total_detections,
                'images_processed': len(images),
                'timestamp': time.time(),
                'image_infos': image_infos,
                'model_info': self.detector_manager.get_active_engine().get_model_info()
            }
            
            if visualized_images:
                result['visualized_images'] = visualized_images
            
            return result
            
        except Exception as e:
            logger.error(f"批量检测失败: {str(e)}")
            raise
    
    def register_model(self, engine_id: str, engine_type: str = 'yolo', 
                      model_path: str = None, device: str = 'auto', 
                      **kwargs) -> bool:
        """注册新模型
        
        Args:
            engine_id: 引擎ID
            engine_type: 引擎类型
            model_path: 模型路径
            device: 运行设备
            **kwargs: 其他配置
            
        Returns:
            bool: 是否注册成功
        """
        try:
            self.detector_manager.create_engine(
                engine_id=engine_id,
                engine_type=engine_type,
                model_path=model_path,
                device=device,
                **kwargs
            )
            logger.info(f"成功注册模型: {engine_id}")
            return True
        except Exception as e:
            logger.error(f"注册模型失败: {str(e)}")
            return False
    
    def set_active_model(self, engine_id: str) -> bool:
        """设置活动模型
        
        Args:
            engine_id: 引擎ID
            
        Returns:
            bool: 是否设置成功
        """
        return self.detector_manager.set_active_engine(engine_id)
    
    def optimize_performance(self, engine_id: Optional[str] = None, **kwargs):
        """优化检测性能
        
        Args:
            engine_id: 引擎ID
            **kwargs: 优化参数
        """
        self.detector_manager.optimize_performance(engine_id, **kwargs)
    
    def get_service_status(self) -> Dict[str, Any]:
        """获取服务状态
        
        Returns:
            Dict: 服务状态信息
        """
        with self._lock:
            # 获取引擎列表
            engines = self.detector_manager.list_engines()
            
            # 获取活动引擎信息
            active_engine = self.detector_manager.get_active_engine()
            active_engine_info = {
                'model_info': active_engine.get_model_info() if active_engine else None,
                'performance_metrics': active_engine.get_performance_metrics() if active_engine else None
            }
            
            status = {
                'service_status': self.service_status,
                'running': self.running,
                'engines': engines,
                'active_engine': active_engine_info,
                'performance_stats': self.performance_stats,
                'result_processor_config': self.result_processor.get_config(),
                'timestamp': time.time()
            }
            
            return status
    
    def reset_tracking(self, engine_id: Optional[str] = None):
        """重置跟踪状态
        
        Args:
            engine_id: 引擎ID，None表示活动引擎
        """
        engine = None
        if engine_id:
            engine = self.detector_manager.get_engine(engine_id)
        else:
            engine = self.detector_manager.get_active_engine()
        
        if engine and hasattr(engine, 'reset_tracking'):
            engine.reset_tracking()
            logger.info(f"已重置引擎 '{engine_id or 'active'}' 的跟踪状态")
        else:
            logger.warning(f"引擎 '{engine_id or 'active'}' 不支持跟踪重置")
    
    def update_result_processor_config(self, config: Dict[str, Any]):
        """
        更新结果处理器配置
        
        Args:
            config: 新的配置
        """
        self.result_processor.update_config(config)
        logger.info("结果处理器配置已更新")
    
    def update_config(self, config: Dict[str, Any]):
        """
        更新检测服务配置
        
        Args:
            config: 新的配置字典，可以包含模型、检测、跟踪等配置
        """
        with self._lock:
            try:
                # 更新服务配置
                if config:
                    self.config.update(config)
                else:
                    # 如果没有提供配置，重新获取配置
                    from config import get_config
                    self.config = get_config()
                
                logger.info("检测服务配置已更新")
                
                # 更新结果处理器配置
                if 'result_processor' in self.config:
                    self.update_result_processor_config(self.config['result_processor'])
                
                # 重新加载默认模型（如果配置了）
                if 'default_models' in self.config and self.config['default_models']:
                    # 检查是否需要重新加载模型
                    self._reload_default_models_if_needed()
                
                return True
            except Exception as e:
                logger.error(f"更新配置失败: {str(e)}", exc_info=True)
                return False
    
    def _reload_default_models_if_needed(self):
        """
        根据配置变化重新加载默认模型
        """
        try:
            default_models = self.config.get('default_models', [])
            current_engines = {engine['engine_id'] for engine in self.detector_manager.list_engines()}
            
            for model_config in default_models:
                engine_id = model_config.get('engine_id', 'default')
                model_path = model_config.get('model_path')
                
                if model_path:
                    if engine_id not in current_engines:
                        # 新模型，加载它
                        logger.info(f"加载新的默认模型: {engine_id} (路径: {model_path})")
                        self.detector_manager.create_engine(
                            engine_id=engine_id,
                            engine_type=model_config.get('engine_type', 'yolo'),
                            model_path=model_path,
                            device=model_config.get('device', 'auto'),
                            **model_config.get('kwargs', {})
                        )
                    else:
                        # 检查是否需要更新现有模型
                        engine = self.detector_manager.get_engine(engine_id)
                        if engine and hasattr(engine, 'update_config'):
                            config_to_update = {
                                k: v for k, v in model_config.items() 
                                if k not in ['engine_id', 'engine_type', 'model_path', 'device']
                            }
                            engine.update_config(config_to_update)
                            logger.info(f"已更新模型 '{engine_id}' 的配置")
        except Exception as e:
            logger.error(f"重新加载模型失败: {str(e)}", exc_info=True)
    
    def auto_optimize(self, target_fps: float = None, target_accuracy: float = None):
        """
        自动优化检测服务性能
        
        Args:
            target_fps: 目标FPS
            target_accuracy: 目标准确率
        """
        try:
            active_engine = self.detector_manager.get_active_engine()
            if active_engine:
                # 获取当前性能指标
                current_metrics = active_engine.get_performance_metrics()
                
                # 根据目标优化
                if target_fps:
                    # 尝试降低分辨率或调整批处理大小
                    # 这是一个简化的实现，实际应该更复杂
                    if hasattr(active_engine, 'set_batch_size'):
                        # 根据需要调整批处理大小
                        pass
                
                # 记录优化操作
                logger.info(f"已执行自动优化，目标FPS: {target_fps}, 目标准确率: {target_accuracy}")
                return True
            return False
        except Exception as e:
            logger.error(f"自动优化失败: {str(e)}", exc_info=True)
            return False
    
    def _prepare_image(self, image: Union[np.ndarray, str]) -> Tuple[np.ndarray, Dict[str, Any]]:
        """准备图像数据
        
        Args:
            image: 输入图像（numpy数组或文件路径）
            
        Returns:
            Tuple[np.ndarray, Dict]: 处理后的图像数组和图像信息
        """
        # 如果是文件路径，读取图像
        if isinstance(image, str):
            image_path = Path(image)
            if not image_path.exists():
                raise FileNotFoundError(f"图像文件不存在: {image}")
            
            # 读取图像
            image_array = cv2.imread(str(image_path))
            if image_array is None:
                raise ValueError(f"无法读取图像: {image}")
            
            # 图像信息
            image_info = {
                'path': str(image_path),
                'filename': image_path.name,
                'shape': image_array.shape,
                'timestamp': time.time()
            }
        else:
            # 假设是numpy数组
            if not isinstance(image, np.ndarray):
                raise TypeError("图像必须是numpy数组或文件路径")
            
            image_array = image
            
            # 图像信息
            image_info = {
                'path': 'input_array',
                'shape': image_array.shape,
                'timestamp': time.time()
            }
        
        return image_array, image_info
    
    def _prepare_detect_kwargs(self, kwargs: Dict[str, Any]) -> Dict[str, Any]:
        """准备检测参数
        
        Args:
            kwargs: 原始参数
            
        Returns:
            Dict: 处理后的检测参数
        """
        detect_kwargs = {}
        
        # 提取相关参数
        if 'confidence_threshold' in kwargs:
            detect_kwargs['confidence_threshold'] = kwargs['confidence_threshold']
        
        if 'nms_threshold' in kwargs:
            detect_kwargs['nms_threshold'] = kwargs['nms_threshold']
        
        if 'target_classes' in kwargs:
            detect_kwargs['target_classes'] = kwargs['target_classes']
        
        if 'mode' in kwargs:
            detect_kwargs['mode'] = kwargs['mode']
        
        return detect_kwargs
    
    def _get_engine_id_by_instance(self, engine) -> Optional[str]:
        """根据引擎实例获取引擎ID
        
        Args:
            engine: 引擎实例
            
        Returns:
            str or None: 引擎ID或None
        """
        engines = self.detector_manager.list_engines()
        for engine_info in engines:
            # 这里简化了实现，实际应该通过引用比较
            if engine_info['engine_id'] == 'active':
                return engine_info['engine_id']
        return None
    
    def _update_performance_stats(self, processing_time: float, detection_count: int):
        """更新性能统计
        
        Args:
            processing_time: 处理时间
            detection_count: 检测数量
        """
        with self._lock:
            # 更新统计数据
            self.performance_stats['total_detections'] += detection_count
            self.performance_stats['total_processing_time'] += processing_time
            
            # 计算平均处理时间
            if self.performance_stats['total_detections'] > 0:
                self.performance_stats['avg_processing_time'] = \
                    self.performance_stats['total_processing_time'] / self.performance_stats['total_detections']
            
            # 计算处理速度
            current_time = time.time()
            elapsed_time = current_time - self.performance_stats['last_reset_time']
            if elapsed_time > 0:
                self.performance_stats['detections_per_second'] = \
                    self.performance_stats['total_detections'] / elapsed_time
    
    def reset_performance_stats(self):
        """重置性能统计"""
        with self._lock:
            self.performance_stats = {
                'total_detections': 0,
                'total_processing_time': 0,
                'avg_processing_time': 0,
                'detections_per_second': 0,
                'last_reset_time': time.time()
            }
            logger.info("性能统计已重置")
    
    def shutdown(self):
        """关闭服务并释放资源"""
        with self._lock:
            self.running = False
            self.service_status = 'stopping'
            
            # 重置所有检测引擎
            self.detector_manager.reset_all_engines()
            
            self.service_status = 'stopped'
            logger.info("检测服务已关闭")

# 创建全局检测服务实例
global_detection_service = None

def get_detection_service() -> DetectionService:
    """获取全局检测服务实例
    
    Returns:
        DetectionService: 全局检测服务实例
    """
    global global_detection_service
    if global_detection_service is None:
        global_detection_service = DetectionService()
    return global_detection_service